﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using Lextm.SharpSnmpLib;
using Lextm.SharpSnmpLib.Security;
using Lextm.SharpSnmpLib.Messaging;
using Lextm.SharpSnmpLib.Mib;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using TopologyWizzard;



namespace VPN_Emulator
{

    //! Klasa reprezentująca główne okno aplikacji
    public partial class MainWindow : Form
    {
        private const String VPN_OID_START = ".1.3.6.1.3.118.1";
        private const String VPN_VRF_OID = ".1.3.6.1.3.118.1.2.2";
        private const String VPN_ROUTE_TARGET_OID = ".1.3.6.1.3.118.1.2.3";
        private const String VPN_VRF_ROUTE_OID = ".1.3.6.1.3.118.1.4.1";

        private Image routerImageCE;
        private Image routerImagePE;
        private Image routerImageP;
        private Image interfaceImage;
        private string path;
        private String iP;
        private SNMPController snmpController;
        private About about;
        private MIBTree MIBtree;
        private List<Router> routerList;
        private Saver saver;
        private ToolTip toolTipInterface;
        private Results resultsWindow;

        private ImageList il = new ImageList();

        //! Konstruktor
        public MainWindow()
        {
            InitializeComponent();
            initResources();
            snmpController = new SNMPController();
            about = new About();
            MIBtree = new MIBTree(this,MainMIBTree);
            TimeoutNumericUpDown.Value = 5000;
            MaxRepetitionNumericUpDown.Value = 10;
            SNMPPortTextBox.Text = "161";
            CommunityTextBox.Text = "zst";
            QueryTypeComboBox.SelectedIndex = 0;
            MIBtree.MIBinitialization(il, path);
            snmpController.MainWindow = this;
        }


        //! Inicjalizacja obiektów
        private void initResources()
        {
            string localPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            path = new Uri(localPath).LocalPath;
            routerImageCE = Image.FromFile(path + "\\Images\\routerIcon.jpg");
            routerImagePE = Image.FromFile(path + "\\Images\\routerIcon3.jpg");
            routerImageP = Image.FromFile(path + "\\Images\\routerIcon2.jpg");
            interfaceImage = Image.FromFile(path + "\\Images\\interfaceIcon.jpg");
            routerList = new List<Router>();
            toolTipInterface = new ToolTip();
            addConsoleText("Start aplication.", Color.Gray);
         
        }

        //! Dodawanie nowego wpisu do panelu konsoli
        public void addConsoleText(string text, Color color)
        {
            DateTime.Now.TimeOfDay.ToString();
            string tex = "[ " + DateTime.Now.Year + "." + DateTime.Now.Month + "." + DateTime.Now.Day +"  " + DateTime.Now.TimeOfDay.ToString() + " ]    " + text;
            console.Items.Add(new MyListBoxItem(color, tex));
            
        }

        //! Obrysowywanie komponentów na panelu topologii
        private void RouterVisualizationPanel_Paint(object sender, PaintEventArgs e)
        {
            for (int i = 0; i < routerList.Count; i++)
            {

                for (int j = 0; j < routerList[i].Interfaces.Count; j++)
                {
                    for (int u = 0; u < routerList[i].Interfaces[j].Connections.Count; u++)
                    {
                        var pen = new Pen(Color.Red, 2);
                        var point1 = new Point(routerList[i].Interfaces[j].X, routerList[i].Interfaces[j].Y + 8);
                        var point2 = new Point(routerList[i].Interfaces[j].Connections[u].XEnd, routerList[i].Interfaces[j].Connections[u].YEnd + 8);
                        e.Graphics.DrawLine(pen, point1, point2);

                    }

                }
            }
        }
       
        //! Wysłanie zapytania SNMP
        private void execute_Click(object sender, EventArgs e)
        
        {
            
            if (OIDTextBox.Text == null || OIDTextBox.Text == "")
            {
                addConsoleText("Invalid OID: ", Color.Blue);
                return;
            }
            string destIp = iP;

            int timeout = Int32.Parse(TimeoutNumericUpDown.Value.ToString());
            string community = CommunityTextBox.Text.ToString();
            int port;

            try
            {
                port = Int32.Parse(SNMPPortTextBox.Text.ToString());
            }

            catch (ErrorException ex)
            {
                console.Items.Add("Error: " + ex);
                port = 161;
            }


            List<string> oidList = new List<string>();
            oidList.Add(OIDTextBox.Text);


            if (OIDTextBox.Text.Length>15 && OIDTextBox.Text.Substring(0, 16) == VPN_OID_START)
            {

                if (QueryTypeComboBox.SelectedItem.ToString() == "Get Table" && OIDTextBox.Text==VPN_VRF_OID)
                {

                    List<List<String>> result_table = snmpController.GetVrfTable(oidList, destIp, port, community, timeout);

                    TableResultDataGridView.Columns.Clear();
                    TableResultDataGridView.Rows.Clear();
                    ValueTextBox.Text = "-";
                    TreeNode[] node = MainMIBTree.Nodes.Find(OIDTextBox.Text, true);
                    DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
                    foreach (System.Windows.Forms.TreeNode i in node[0].Nodes[0].Nodes)
                    {
                        DataGridViewColumn column = new DataGridViewColumn();
                        column.HeaderText = column.Name = i.Text;
                        column.ReadOnly = true;
                        column.CellTemplate = cell;
                        TableResultDataGridView.Columns.Add(column);
                    }
                   

                    for (int col = 0; col < result_table[0].Count; col++)
                    {
                        String[] temp = new string[result_table.Count];
                        for (int row = 0; row < result_table.Count; row++)
                        {
                            temp[row]=result_table[row][col];
                        }
                        TableResultDataGridView.Rows.Add(temp);
                    }
                }
                if (QueryTypeComboBox.SelectedItem.ToString() == "Get Table" && OIDTextBox.Text == VPN_ROUTE_TARGET_OID)
                {

                    List<List<String>> result_table = snmpController.GetRouteTargetTable(oidList, destIp, port, community, timeout);

                    TableResultDataGridView.Columns.Clear();
                    TableResultDataGridView.Rows.Clear();
                    ValueTextBox.Text = "-";
                    TreeNode[] node = MainMIBTree.Nodes.Find(OIDTextBox.Text, true);
                    DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
                    foreach (System.Windows.Forms.TreeNode i in node[0].Nodes[0].Nodes)
                    {
                        DataGridViewColumn column = new DataGridViewColumn();
                        column.HeaderText = column.Name = i.Text;
                        column.ReadOnly = true;
                        column.CellTemplate = cell;
                        TableResultDataGridView.Columns.Add(column);
                    }


                    for (int col = 0; col < result_table[0].Count; col++)
                    {
                        String[] temp = new string[result_table.Count];
                        for (int row = 0; row < result_table.Count; row++)
                        {
                            temp[row] = result_table[row][col];
                        }
                        TableResultDataGridView.Rows.Add(temp);
                    }
                }
                if (QueryTypeComboBox.SelectedItem.ToString() == "Get Table" && OIDTextBox.Text == VPN_VRF_ROUTE_OID)
                {

                    List<List<String>> result_table = snmpController.GetVpnVrfRouteTable(oidList, destIp, port, community, timeout);

                    TableResultDataGridView.Columns.Clear();
                    TableResultDataGridView.Rows.Clear();
                    ValueTextBox.Text = "-";
                    TreeNode[] node = MainMIBTree.Nodes.Find(OIDTextBox.Text, true);
                    DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
                    foreach (System.Windows.Forms.TreeNode i in node[0].Nodes[0].Nodes)
                    {
                        DataGridViewColumn column = new DataGridViewColumn();
                        column.HeaderText = column.Name = i.Text;
                        column.ReadOnly = true;
                        column.CellTemplate = cell;
                        TableResultDataGridView.Columns.Add(column);
                    }


                    for (int col = 0; col < result_table[0].Count; col++)
                    {
                        String[] temp = new string[result_table.Count];
                        for (int row = 0; row < result_table.Count; row++)
                        {
                            temp[row] = result_table[row][col];
                        }
                        TableResultDataGridView.Rows.Add(temp);
                    }
                }
            }
            else
            {
                if (QueryTypeComboBox.SelectedItem.ToString() == "Get")
                {
                    List<Variable> result = snmpController.Get(oidList, destIp, port, community, timeout);
                    try
                    {
                        addConsoleText("GetResponse: " + result[0].Data.ToString(), Color.Blue);
                        ValueTextBox.Text = result[0].Data.ToString();
                        TableResultDataGridView.Columns.Clear();
                        TableResultDataGridView.Rows.Clear();
                        
                        
                    }
                    catch (ArgumentOutOfRangeException ex)
                    {
                    }

                }
                else if (QueryTypeComboBox.SelectedItem.ToString() == "Get Next")
                {
                    List<Variable> result = snmpController.GetNext(oidList, destIp, port, community, timeout);
                    try
                    {
                        addConsoleText("GetResponse: " + result[0].Data.ToString(), Color.Blue);
                        ValueTextBox.Text = result[0].Data.ToString();
                        TableResultDataGridView.Columns.Clear();
                        TableResultDataGridView.Rows.Clear();
                    }
                    catch (ArgumentOutOfRangeException ex)
                    {
                    }
                }
                else if (QueryTypeComboBox.SelectedItem.ToString() == "Get Bulk")
                {
                    try
                    {
                        List<Variable> result = snmpController.GetBulk(oidList, destIp, port, community, Int32.Parse(MaxRepetitionNumericUpDown.Value.ToString()), Int32.Parse(NonRepetersNumericUpDown.Value.ToString()), timeout);
                        addConsoleText("GetResponse: " + result[0].Data.ToString(), Color.Blue);
                    }
                    catch (ArgumentOutOfRangeException ex)
                    {
                    }
                }
                else if (QueryTypeComboBox.SelectedItem.ToString() == "Get Table")
                {
                    Variable[,] result = snmpController.GetTable(OIDTextBox.Text.ToString(), destIp, port, community, Int32.Parse(MaxRepetitionNumericUpDown.Value.ToString()), timeout);
                    TreeNode[] node = MainMIBTree.Nodes.Find(OIDTextBox.Text, true);
                    addConsoleText("GetResponse came", Color.Blue);
                    TableResultDataGridView.Columns.Clear();
                    TableResultDataGridView.Rows.Clear();
                    ValueTextBox.Text = "-";
                    if (result != null)
                    {
                        DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
                        foreach (System.Windows.Forms.TreeNode i in node[0].Nodes[0].Nodes)
                        {
                            DataGridViewColumn column = new DataGridViewColumn();
                            column.HeaderText = column.Name = i.Text;
                            column.ReadOnly = true;
                            column.CellTemplate = cell;
                            TableResultDataGridView.Columns.Add(column);
                        }

                        string[] res = new string[result.GetUpperBound(1) + 1];
                        for (int row = 0; row <= result.GetUpperBound(0); row++)
                        {
                            for (int col = 0; col <= result.GetUpperBound(1); col++)
                            {
                                res[col] = result[row, col].Data.ToString();
                            }
                            TableResultDataGridView.Rows.Add(res);
                        }

                    }
                }
            }
            

        }

        //! Zmiana wyboru operacji SNMP
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (QueryTypeComboBox.SelectedItem.ToString() == "Get Bulk")
            {
                MaxRepetitionNumericUpDown.Enabled = true;
                NonRepetersNumericUpDown.Enabled = true;
            }

            else if (QueryTypeComboBox.SelectedItem.ToString() == "Get Table")
            {
                MaxRepetitionNumericUpDown.Enabled = true;
                NonRepetersNumericUpDown.Enabled = false;
            }
            else
            {
                MaxRepetitionNumericUpDown.Enabled = false;
                NonRepetersNumericUpDown.Enabled = false;
            }
        }

        //! Wyjście z aplikacji
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        //! Otworzenie okna About
        private void helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            about.ShowDialog();
            
        }

        //! Wybranie 
        private void MainMIBTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            {
                if (MainMIBTree.SelectedNode.ImageIndex == 1 || MainMIBTree.SelectedNode.ImageIndex == 4)
                {
                    OIDTextBox.Text = MainMIBTree.SelectedNode.Name + ".0";
                    if (QueryTypeComboBox.SelectedIndex == 3)
                    {
                        QueryTypeComboBox.SelectedIndex = 0;
                    }
                }
                else if (MainMIBTree.SelectedNode.ImageIndex == 0 || MainMIBTree.SelectedNode.ImageIndex == 5)
                {

                }
                else
                {
                    if (MainMIBTree.SelectedNode.ImageIndex == 2)
                    { QueryTypeComboBox.SelectedIndex = 3; }
                    OIDTextBox.Text = MainMIBTree.SelectedNode.Name;
                }
            }
        }

        //! Wczytanie topologii sieci
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openToolStripMenuItem.Enabled = false;
            OpenFileDialog openFile1 = new OpenFileDialog();

			openFile1.DefaultExt = "*.vpn";
			openFile1.Filter = "VPN Files|*.vpn";



            if (openFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
                openFile1.FileName.Length > 0)
            {
                BinaryFormatter formatter;
                FileStream fs = new FileStream(openFile1.FileName, FileMode.Open);
                formatter = new BinaryFormatter();
                saver = (Saver)(formatter.Deserialize(fs));
                fs.Close();


                routerList.Clear();
                RouterVisualizationPanel.Controls.Clear();

                for (int i = 0; i < saver.Routers.Count; i++)
                {
                    Router router = new Router(saver.Routers[i].Name, saver.Routers[i].IpAddress, saver.Routers[i].X, saver.Routers[i].Y);
                    router.TestCaseList = saver.Routers[i].TestCaseList;
                    router.Interfaces = new List<Interface>(saver.Routers[i].Interfaces.Count);

                    for (int j = 0; j < saver.Routers[i].Interfaces.Count; j++)
                    {
                        Interface inter = new Interface(saver.Routers[i].Interfaces[j].Name, saver.Routers[i].Interfaces[j].X, saver.Routers[i].Interfaces[j].Y, saver.Routers[i].Interfaces[j].Connections);
                        router.Interfaces.Add(inter);
                    }

                    System.Windows.Forms.PictureBox temp = new System.Windows.Forms.PictureBox();
                    switch (saver.Routers[i].Which)
                    {
                        case 1:
                            temp.Image = routerImageCE;
                            break;
                        case 2:
                            temp.Image = routerImagePE;
                            break;
                        case 3:
                            temp.Image = routerImageP;
                            break;
                    }
                    temp.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
                    temp.BackColor = System.Drawing.Color.White;
                    temp.Name = router.Name;
                    temp.TabIndex = 0;
                    temp.TabStop = false;
                    temp.Location = new System.Drawing.Point(router.XPossition, router.YPossition);
                    temp.Click += new System.EventHandler(this.routerImageClick);
                    temp.DoubleClick += new System.EventHandler(this.routerImageDoubleClick);
                    temp.Size = new System.Drawing.Size(routerImageCE.Width, routerImageCE.Height);
                    router.PictureBox = temp;

                    routerList.Add(router);


                    for (int j = 0; j < saver.Routers[i].Interfaces.Count; j++)
                    {
                        System.Windows.Forms.PictureBox tempI = new System.Windows.Forms.PictureBox();
                        tempI.Image = interfaceImage;
                        tempI.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
                        tempI.BackColor = System.Drawing.Color.White;
                        tempI.Name = router.Interfaces[j].Name;
                        tempI.TabIndex = 0;
                        tempI.TabStop = false;
                        tempI.Size = new System.Drawing.Size(interfaceImage.Width, interfaceImage.Height);

                        tempI.Location = new System.Drawing.Point(router.Interfaces[j].X, router.Interfaces[j].Y);
                        tempI.Click += new System.EventHandler(this.interfaceImageClick);
                        tempI.MouseHover += new System.EventHandler(interface_MouseHover);
                        tempI.MouseLeave += new System.EventHandler(interface_MouseLeave);

                        router.Interfaces[j].PictureBox = tempI;
                        RouterVisualizationPanel.Controls.Add(tempI);

                        for (int u = 0; u < saver.Routers[i].Interfaces[j].Connections.Count; u++)
                        {
                            Graphics g = RouterVisualizationPanel.CreateGraphics();
                            var pen = new Pen(Color.Red, 2);
                            var point1 = new Point(saver.Routers[i].Interfaces[j].X, saver.Routers[i].Interfaces[j].Y + 8);
                            var point2 = new Point(saver.Routers[i].Interfaces[j].Connections[u].XEnd, saver.Routers[i].Interfaces[j].Connections[u].YEnd + 8);
                            g.DrawLine(pen, point1, point2);

                        }

                    }
                    RouterVisualizationPanel.Controls.Add(temp);
                }
            }

          
        }

        //! Kliknięcie na ikonę routera - wypisanie parametrów routera
        public void routerImageClick(object sender, System.EventArgs e)
        {
            //Sprawdzenie ktory zostal klikniety
            foreach (Router r in routerList)
            {
                if (sender.Equals(r.PictureBox))
                {
                    
                    RouterNameTextBox.Text = r.Name;
                    RouterIPAddressTextBox.Text = r.IPAddress;
                    iP = r.IPAddress;

                    r.PictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
              
                }

                else
                {
                    r.PictureBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
                }
            }
        }

        //! Podwójne kliknięcie na ikonę routera - otworzenie konsoli Telnet
        public void routerImageDoubleClick(object sender, System.EventArgs e)
        {
            //Sprawdzenie ktory zostal klikniety
            foreach (Router r in routerList)
            {
                if (sender.Equals(r.PictureBox))
                {
                    System.Diagnostics.Process.Start("C:/windows/sysnative/telnet.exe", iP + " 23");
                    addConsoleText("Telnet connect to: " + iP, Color.Blue);
                }

            }

        }

        //! Klieknięcie na interfejs - wypisanie parametrów interfejsu
        public void interfaceImageClick(object sender, System.EventArgs e)
        {
            //Sprawdzenie ktory zostal klikniety
            foreach (Router r in routerList)
            {
                for (int i = 0; i < r.Interfaces.Count; i++)
                {
                    if (sender.Equals(r.Interfaces[i].PictureBox))
                    {

                        InterfaceNameTextBox.Text = r.Interfaces[i].Name;
                        InterfaceRouterTextBox.Text = r.Name;
                        r.Interfaces[i].PictureBox.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;

                    }

                    else
                    {
                        r.Interfaces[i].PictureBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
                    }
                }
            }
        }

        //! Zdarzenie najechania kursorem na ikonę Routera - wyświetlenie ToolTip
        public void interface_MouseHover(object sender, EventArgs e)
        {
            toolTipInterface.ToolTipTitle = "Interface";
             foreach (Router r in routerList)
            {
                for (int i = 0; i < r.Interfaces.Count; i++)
                {
                    if (sender.Equals(r.Interfaces[i].PictureBox))
                    {
                        toolTipInterface.Show("Interface Name: " + r.Interfaces[i].Name, this, r.Interfaces[i].X, r.Interfaces[i].Y); 
                    }
                }
            }
        }

        //! Zdarzenie opuszczenia myszą ikony Routera - ukrycie ToolTip
        public void interface_MouseLeave(object sender, EventArgs e)
        {
            toolTipInterface.Hide(this);
        }

        //! Wielowątkowa funkcja weryfikacji laboratorium
        public bool checkIt()
        {
            List<Thread> threadList = new List<Thread>();
            foreach (Router rout in routerList)
            {
                foreach (TestCase tc in rout.TestCaseList)
                {
                    Thread tmpThr = new Thread(new ParameterizedThreadStart(this.checkItTest));
                    threadList.Add(tmpThr);
                    tmpThr.Start(tc);

                }
            }

            foreach (Thread thr in threadList)
            {
                thr.Join();
            }
            

            resultsWindow = new Results();       
            resultsWindow.RouterList = routerList;
            resultsWindow.getResult();
            resultsWindow.ShowDialog();
            return true;
        }

        //! Wysłanie zapytań w celu weryfikacji laboratorium 
        public void checkItTest(Object obj)
        {
            string destIp = iP;


            int timeout = Int32.Parse(TimeoutNumericUpDown.Value.ToString());
            string community = CommunityTextBox.Text.ToString();
            int port;

            try
            {
                port = Int32.Parse(SNMPPortTextBox.Text.ToString());
            }

            catch (ErrorException ex)
            {
                console.Items.Add("Error: " + ex);
                port = 161;
            }

            TestCase tc = (TestCase)obj;

            tc.Correct = true;

            if (tc.GetType == "Get")
            {
                List<string> oidList = new List<string>();
                oidList.Add(tc.Oid);

                string result;
                result = snmpController.snmpGet(oidList, tc, port, community)[0].Data.ToString();
                if (result != null)
                {
                    int number = 0;
                    bool ok = false;
                    foreach (KeyValuePair<int, string> kvp in tc.getExpectedAttr())
                    {
                        if (result == kvp.Value)
                        {
                            tc.Result=true;
                            tc.ResultAttr[number] = true;
                            ok = true;
                        }
                        else if(ok==false)
                        {
                            tc.Result=false;
                        }
                        number++;
                       
                    }
                }
                else
                {
                   
                    tc.Correct = false;
                    return;
                }
            }
            else if (tc.GetType == "GetTable")
            {
                //pobranie tablicy
                Variable[,] addTable = snmpController.snmpGetTable(tc.Oid,port,community,10,tc);
                if (addTable != null)
                {
                    int valueNumber = 0;

                    for (int row = 0; row <= addTable.GetUpperBound(0); row++)
                    {
                        valueNumber = 0;
                        int number = 0;
                        foreach (KeyValuePair<int, string> kvp in tc.getExpectedAttr())
                        {
                            
                            if (addTable[row, kvp.Key].Data.ToString() == kvp.Value)
                            {
                                valueNumber = valueNumber + 1;
                                tc.ResultAttr[number] = true;
                            }
                            number++;
                        }

                        if (valueNumber == tc.getExpectedAttr().Count)
                        {
                            tc.Result=true;
                            break;
                        }
                    }
                }
                else
                {
                   
                    tc.Correct = false;
                    return;
                }
            }

           

        }

        //! Odrysowanie wpisów w panelu konsoli
        private void console_DrawItem(object sender, DrawItemEventArgs e)
        {
            MyListBoxItem item = console.Items[e.Index] as MyListBoxItem; 
            if (item != null)
            {
                e.Graphics.DrawString( 
                    item.Message, 
                    console.Font, 
                    new SolidBrush(item.ItemColor), 
                    0, 
                    e.Index * console.ItemHeight 
                );
            }
        }

        //! Wyczyszczenie zawartości panelu konsoli
        private void clear_Click(object sender, EventArgs e)
        {
            console.Items.Clear();
        }

        //! Kliknięcie przycisku weryfikacji
        private void verifi_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Czy na pewno chcesz zakończyć laboratorium i wyświetlić wyniki?", "Weryfikacja", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;
            checkIt();
        }


    };
}
